package ArithmeticObjects;
import java.util.*;

import utils.ByteTree;

/**
 * Representing an array of modular group elements
 * @author Idan
 */
public class ModularGroupArray extends ElementArray {

	private List<ModularGroupElement> lst;
	private Group Gq;
	
	/**
	 * helper method to create an array of ModularGroupElements from the given ByteTree
	 * representing it and a Group indicating its order
	 * @param bt ByteTree representing the array of ModularGroupElements
	 * @param Gq Group indicating its order
	 * @return the list of elements in the array
	 * @throws Exception if the construction failed
	 */
	private static List<ModularGroupElement> getList(ByteTree bt, Group Gq) throws Exception {
		List<ModularGroupElement> lstTemp = new ArrayList<ModularGroupElement>();
		for (int i=0; i < bt.getNumOfChildren(); i++)
			lstTemp.add(new ModularGroupElement(bt.getChild(i), Gq));
		return lstTemp;
	}
	
	/**
	 * creates a ModularGroupArray from a ByteTree representing it and a Group indicating its order
	 * @param bt ByteTree representing the ModularGroupArray
	 * @param Gq Group indicating its order
	 * @throws Exception if the construction failed
	 */
	public ModularGroupArray(ByteTree bt, Group Gq) throws Exception {
		this.Gq = Gq;
		lst = getList(bt, Gq);
	}
	
	/**
	 * creates a ModularGroupArray from an array of elements and a Group indicating its order
	 * @param elements Array of ModularGroupElements
	 * @param Gq Group indicating its order
	 * @throws Exception if the construction failed
	 */
	public ModularGroupArray(Element[] elements, Group Gq) throws Exception {
		this.Gq = Gq;
		lst = new ArrayList<ModularGroupElement>();
		for (int i=0; i < elements.length; i++)
			lst.add(new ModularGroupElement(elements[i].getValue(), Gq));
	}
	
	/**
	 * creates an empty ModularGroupArray
	 * @param Gq Group indicating its order
	 * @throws Exception if the construction failed
	 */
	public ModularGroupArray(Group Gq) throws Exception {
		lst = new ArrayList<ModularGroupElement>();
		this.Gq = Gq;
	}
	
	@Override
	public void addElement(Element element) throws Exception {
		if (!(element instanceof ModularGroupElement))
			throw new Exception("Wrong class, Expected: ModularGroupElement, got: " 
		+ Gq.getOrder().getClass().getName());
		lst.add((ModularGroupElement)element);
	}
	
	@Override
	public ElementArray arrayMultiply(ElementArray Ea) throws Exception {
		if (this.getArraySize()!=(Ea.getArraySize()))
			throw new Exception("Cannot multiply arrays of different sizes");
		
		Element[] arr=new Element[this.getArraySize()];
		for (int i=0; i<this.getArraySize(); i++)
			arr[i]=this.getElementForIndex(i).multiply(Ea.getElementForIndex(i));
		return new ModularGroupArray(arr, Gq);
	}
	
	@Override
	public Element getElementForIndex(int i) {
		return lst.get(i);
	}
	
	/**
	 * @return the ModularGroupArray's order
	 */
	public Element getOrder() {
		return Gq.getOrder();
	}
	
	@Override
	public int getArraySize() {
		return lst.size();
	}
	
	@Override
	public String toString() {
		String s = "";
		for (int i=0; i<lst.size(); i++)
			s += lst.get(i).toString()+"\n";
		return s;
	}

	@Override
	public ByteTree getByteTree() throws Exception {
		Element[] arr = new Element[this.getArraySize()];
		lst.toArray(arr);
		return ByteTree.createArrayByteTree(arr,(Gq.getOrder().value.bitLength() + 7) / 8);
	}
}
